home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Diamond Collection / The Diamond Collection (Software Vault)(Digital Impact).ISO / cdr34 / mime64b.zip / MIME64.C < prev    next >
Text File  |  1995-02-01  |  19KB  |  787 lines

  1. /* mime64 */
  2. /* MIME base64 encoder/decoder by Karl Hahn  hahn@lds.loral.com  3-Aug-94 */
  3. /* modified 30-Sep-94 by Karl Hahn hahn@lds.loral.com: handle multiple
  4.    content */
  5. /* modified 12-Jan-95 by Karl Hahn hahn@lds.loral.com: handle file names
  6.    that are encased in quotes */
  7. /* modified 18-Jan-95 by Karl Hahn hahn@lds.loral.com: prevent complete
  8.    failure if filename in name field matches name of input file */
  9. /* modified 19-Jan-95 by Karl Hahn hahn@lds.loral.com: prevent early exit
  10.    if last decoded character falls on a multiple of 3 -- would cause error
  11.    message and failure to rename output file if rename was necessary */
  12. /* modified 19-Jan-95 by Karl Hahn hahn@lds.loral.com: prevent complete
  13.    failure if a line of text preceding the MIME64 stuff contains no
  14.    non-base64 characters */
  15. /* modified 19-Jan-95 by Karl Hahn hahn@lds.loral.com: fixed command
  16.    line parser to prevent missing a name field preceded by another
  17.    name field */
  18. /* modified 19-Jan-95 by Karl Hahn hahn@lds.loral.com: prevent error
  19.    message at the end of decoding each section.  Terminates output
  20.    file now on a blank line as well as the conditions that did so
  21.    previously */
  22.  
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26.  
  27. char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
  28.                   "0123456789+/";
  29.  
  30. enum TOKENTYPE { NONE, BLANKS, PUNCT, TAG, NAME, CONTENT };
  31.  
  32. struct TOKEN {
  33.                 char *text;
  34.                 int  length;
  35.                 int  index;
  36.                 enum TOKENTYPE type;
  37.              };
  38.  
  39. int compare_token( struct TOKEN *token, char *text )
  40. {
  41.    int index=0;
  42.    int count;
  43.    int result;
  44.    char blivit1, blivit2;
  45.  
  46.    count = token->length;
  47.  
  48.    if ( count > 0 )
  49.    {
  50.       result = 1;
  51.    }
  52.    else
  53.    {
  54.       result = 0;
  55.    }
  56.  
  57.    while ( (count > 0) && ( result != 0 ) )
  58.    {
  59.       blivit1 = token->text[index++];
  60.       if ( (blivit1 >= 'a' ) && (blivit1 <= 'z') )
  61.       {
  62.          blivit1 -= ' ';
  63.       }
  64.  
  65.       blivit2 = *text++;
  66.       if ( (blivit2 >= 'a' ) && (blivit2 <= 'z') )
  67.       {
  68.          blivit2 -= ' ';
  69.       }
  70.  
  71.       if ( blivit1 != blivit2 )
  72.       {
  73.          result = 0;
  74.       }
  75.  
  76.       count--;
  77.    }
  78.  
  79.    return result;
  80. }
  81.  
  82. int ispunct( char blivit )
  83. {
  84.    if ( ( blivit >= 'a' ) && (blivit <= 'z' ) )
  85.    {
  86.       blivit -= ' ';
  87.    }
  88.  
  89.    if ( ( ( blivit < '0' ) ||
  90.           ( ( blivit > '9' ) && (blivit < 'A') ) ||
  91.           ( blivit > 'Z' ) ) &&
  92.         ( blivit != '-') && (blivit != '/') && (blivit != '.') )
  93.    {
  94.       return 1;
  95.    }
  96.    else
  97.    {
  98.       return 0;
  99.    }
  100. }
  101.  
  102. void fixname( char *name )
  103. {
  104.    while ( *name != '\0' )
  105.    {
  106.  
  107.      if (ispunct( *name ) )
  108.      {
  109.         *name = '\0';
  110.      }
  111.  
  112.      name++;
  113.    }
  114. }
  115.  
  116. void acquire_token( char *line, enum TOKENTYPE type, struct TOKEN *token )
  117. {
  118.    int doneflag=0, startflag=1;
  119.    int index;
  120.    enum TOKENTYPE nextstate=NONE;
  121.    char blivit;
  122.  
  123.    if (token->type == NONE)
  124.    {
  125.       token->index = 0;
  126.       token->length = 0;
  127.    }
  128.  
  129.    index = token->index + token->length;
  130.  
  131.    token->text = 0;
  132.  
  133.    while ( doneflag == 0 )
  134.    {
  135.       blivit = line[index];
  136.       if ( (blivit >= 'a') && (blivit <= 'z') )
  137.       {
  138.          blivit -= ' ';
  139.       }
  140.  
  141.       switch (token->type)
  142.       {
  143.          case NONE:
  144.          if ( blivit == ' ')
  145.          {
  146.             index++;
  147.             token->index++;
  148.          }
  149.          else
  150.          {
  151.             token->type = TAG;
  152.             nextstate = TAG;
  153.          }
  154.          break;
  155.  
  156.          case BLANKS:
  157.          if      ( blivit == ' ')
  158.          {
  159.             index++;
  160.          }
  161.          else if ( ispunct( blivit ) )
  162.          {
  163.             token->type = PUNCT;
  164.             token->index = index;
  165.          }
  166.          else
  167.          {
  168.             token->type = nextstate;
  169.             token->index = index;
  170.          }
  171.          break;
  172.  
  173.          case PUNCT:
  174.          if      ( blivit <  ' ')
  175.          {
  176.             doneflag = 1;
  177.             token->type = NONE;
  178.             token->index = index;
  179.             token->text = line + index;
  180.             token->length = 0;
  181.          }
  182.          else if ( blivit == ' ' )
  183.          {
  184.             token->type = BLANKS;
  185.             token->index = index;
  186.             if      ( line[ token->index ] == ';' )
  187.             {
  188.                nextstate = NAME;
  189.             }
  190.             else if ( line[ token->index ] == '=' )
  191.             {
  192.                nextstate = CONTENT;
  193.             }
  194.  
  195.          }
  196.          else if ( ispunct( blivit ) )
  197.          {
  198.             index++;
  199.          }
  200.          else
  201.          {
  202.             if      ( line[ token->index ] == ';' )
  203.             {
  204.                nextstate = NAME;
  205.             }
  206.             else if ( line[ token->index ] == '=' )
  207.             {
  208.                nextstate = CONTENT;
  209.             }
  210.  
  211.             token->type = nextstate;
  212.             token->index = index;
  213.          }
  214.          break;
  215.  
  216.          case TAG:
  217.          if ( ispunct( blivit ) )
  218.          {
  219.             token->length = index - token->index;
  220.             token->text = line + token->index;
  221.             nextstate = NAME;
  222.  
  223.             if ( ( ( type == TAG ) || ( type == NONE ) ) && !startflag)
  224.             {
  225.                doneflag = 1;
  226.             }
  227.             else if (blivit == ' ')
  228.             {
  229.                token->type = BLANKS;
  230.                token->index = index;
  231.             }
  232.             else
  233.             {
  234.                token->type = PUNCT;
  235.                token->index = index;
  236.             }
  237.          }
  238.          else
  239.          {
  240.             index++;
  241.          }
  242.          break;
  243.  
  244.          case NAME:
  245.          if ( ispunct( blivit ) )
  246.          {
  247.             token->length = index - token->index;
  248.             token->text = line + token->index;
  249.  
  250.             if ( blivit != ';' )
  251.             {
  252.                nextstate = CONTENT;
  253.             }
  254.             else
  255.             {
  256.                nextstate = NAME;
  257.             }
  258.  
  259.             if ( ( ( type == NAME ) || ( type == NONE ) ) && !startflag )
  260.             {
  261.                doneflag = 1;
  262.             }
  263.             else if (blivit == ' ')
  264.             {
  265.                token->type = BLANKS;
  266.                token->index = index;
  267.             }
  268.             else
  269.             {
  270.                token->type = PUNCT;
  271.                token->index = index;
  272.             }
  273.          }
  274.          else
  275.          {
  276.             index++;
  277.          }
  278.          break;
  279.  
  280.          case CONTENT:
  281.          if ( ispunct( blivit ) )
  282.          {
  283.             token->length = index - token->index;
  284.             token->text = line + token->index;
  285.             nextstate = NAME;
  286.  
  287.             if ( ( ( type == CONTENT ) || ( type == NONE ) ) && !startflag )
  288.             {
  289.                doneflag = 1;
  290.             }
  291.             else if (blivit == ' ')
  292.             {
  293.                token->type = BLANKS;
  294.                token->index = index;
  295.             }
  296.             else
  297.             {
  298.                token->type = PUNCT;
  299.                token->index = index;
  300.             }
  301.          }
  302.          else
  303.          {
  304.             index++;
  305.          }
  306.          break;
  307.       }
  308.       startflag = 0;
  309.    }
  310. }
  311.  
  312. void fputch( char blivit, FILE *f )
  313. {
  314. /*   if (blivit == '\n') fputc( '\r', f );*/
  315.    fputc( blivit, f );
  316. }
  317.  
  318. int classify_args( int narg,
  319.                    char *rawargs[], char *fileargs[], char *optargs[] )
  320. {
  321.    int index, jndex, kndex;
  322.    char *argptr;
  323.  
  324.    for ( index = 0, jndex = 0, kndex = 0; index < narg; index++ )
  325.    {
  326.       argptr = rawargs[index];
  327.       if (*argptr == '-')
  328.       {
  329.          argptr++;
  330.          optargs[kndex++] = argptr;
  331.       }
  332.       else
  333.       {
  334.          fileargs[jndex++] = argptr;
  335.       }
  336.    }
  337.  
  338.    return kndex;
  339. }
  340.  
  341. int cvt_ascii( unsigned char alpha )
  342. {
  343.    if      ( (alpha >= 'A') && (alpha <= 'Z') ) return (int)(alpha - 'A');
  344.    else if ( (alpha >= 'a') && (alpha <= 'z') )
  345.         return 26 + (int)(alpha - 'a');
  346.    else if ( (alpha >= '0') && (alpha <= '9' ) )
  347.         return 52 + (int)(alpha - '0');
  348.    else if ( alpha == '+' ) return 62;
  349.    else if ( alpha == '/' ) return 63;
  350.    else if ( alpha == '=' ) return -2;
  351.    else                     return -1;
  352. }
  353.  
  354. char *fileargs[64], *optargs[64];
  355.  
  356. struct STATE64 {
  357.                   unsigned long int accum;
  358.                   int               shift;
  359.                };
  360.  
  361.  
  362. int main( int nargs, char *cargs[] )
  363. {
  364.    int n_options, n_files, index, jndex, shift, save_shift;
  365.    enum { ENCODE, DECODE } whattodo = DECODE;
  366.    int help_flag = 0, replace_flag = 0, perm_replace_flag = 0, quit = 0;
  367.    int cycle_flag = 0;
  368.    FILE *fin, *fout, *dummy;
  369.    unsigned char blivit;
  370.    unsigned long accum, value;
  371.    char buf[80], dumname[80];
  372.    char *cptr, *altptr;
  373.    int decode_state;
  374.    struct TOKEN token;
  375.    int firsttime = 1;
  376.    int skipflag = 0;
  377.    int printmsg = 1;
  378.  
  379.    n_options = classify_args( nargs, cargs, fileargs, optargs );
  380.  
  381.    n_files = nargs - n_options;
  382.  
  383.    if ( n_files < 2 ) help_flag = 1;
  384.  
  385.    for ( index = 0; index < n_options; index++ )
  386.    {
  387.       if ( ( optargs[index][0] == 'e' ) ||
  388.            ( optargs[index][0] == 'E' ) ) whattodo = ENCODE;
  389.       if ( optargs[index][0] == '?' ) help_flag = 1;
  390.    }
  391.  
  392.    if ( help_flag )
  393.    {
  394.       printf( "mime64 infile [outfile] [-option] [-option] etc.\n\n"
  395.               "convert between binary and MIME BASE64 format\n\n"
  396.               "        -e       MIME base64 encode (default is decode)\n"
  397.               "        -?       display help message\n\n"
  398.               "if no outfile given, output file replaces infile\n" );
  399.    }
  400.  
  401.    if ( n_files < 2 ) exit(0);
  402.  
  403.    if ( whattodo == DECODE )
  404.    {
  405.       fin = fopen( fileargs[1], "r" );
  406.    }
  407.    else
  408.    {
  409.       fin = fopen( fileargs[1], "rb" );
  410.    }
  411.  
  412.    if ( fin == 0 )
  413.    {
  414.       printf( "%s file not found\n", fileargs[1] );
  415.       exit(-1);
  416.    }
  417.  
  418.    if ( n_files > 2 )
  419.    {
  420.       if ( whattodo == DECODE )
  421.       {
  422.          sprintf( dumname, "%s", fileargs[2] );
  423.       }
  424.       else
  425.       {
  426.          fout = fopen( fileargs[2], "w" );
  427.       }
  428.  
  429.       if ( fout == 0 )
  430.       {
  431.          printf( "Couldn't open %s for output\n", fileargs[2] );
  432.       }
  433.    }
  434.    else
  435.    {
  436.       if ( whattodo == DECODE )
  437.       {
  438.          sprintf( dumname, "%s", fileargs[1] );
  439.       }
  440.       else
  441.       {
  442.          fout = fopen( "$$$$$$$$.$$$", "w" );
  443.       }
  444.  
  445.       replace_flag = 1;
  446.    }
  447.  
  448.  
  449. do {
  450.    quit = 0;
  451.    printmsg = 1;
  452.  
  453.    if ( whattodo == DECODE )
  454.    {
  455.       shift = 0;
  456.       accum = 0;
  457.       decode_state = 0;
  458.  
  459.       while ( ( !feof( fin ) ) && (quit == 0) )
  460.       {
  461.          fgets( buf, 80, fin );
  462.          if ( feof( fin ) )
  463.          {
  464.             if ( ( dumname[0] != '\0' ) && ( shift != 0 ) )
  465.             {
  466.                printf( "Unexpected end of file encountered in %s\n"
  467.                        "last few bytes may have been lost\n", dumname );
  468.                quit = 1;
  469.                decode_state = 1;
  470.                continue;
  471.             }
  472.             else if ( cycle_flag == 0 )
  473.             {
  474.                quit = 1;
  475.                decode_state = 1;
  476.                continue;
  477.             }
  478.          }
  479.          else
  480.          {
  481.             cycle_flag = 1;
  482.  
  483.             if ( (decode_state == 1) &&
  484.                  ( (buf[0] == '\n') || (buf[0] < '+') ) )
  485.             {
  486.                quit = 1;
  487.  
  488.                if ( shift != 0 )
  489.                {
  490.                   printf( "Unexpected end of section in %s\n"
  491.                           "last few bytes may have been lost\n", dumname );
  492.                }
  493.  
  494.                continue;
  495.             }
  496.          }
  497.  
  498.  
  499.          if ( decode_state == 0 )
  500.          {
  501.             for ( index = 0;
  502.                   (buf[index] != '\n') && (buf[index] != '\0') &&
  503.                   (decode_state >= 0);
  504.                   index++ )
  505.             {
  506.                if ( ( (buf[index] >= 'A') && (buf[index] <= 'Z') ) ||
  507.                     ( (buf[index] >= 'a') && (buf[index] <= 'z') ) ||
  508.                     ( (buf[index] >= '0') && (buf[index] <= '9') ) ||
  509.                     (buf[index] == '+') ||
  510.                     (buf[index] == '/') ||
  511.                     (buf[index] == '=') )
  512.                {
  513.                   decode_state = 1;
  514.                }
  515.                else
  516.                {
  517.                   decode_state = -2;
  518.                }
  519.             }
  520.  
  521.             if ( decode_state <= 0 )
  522.             {
  523.  
  524.                decode_state = 0;
  525.                token.type = NONE;
  526.  
  527.                acquire_token( buf, TAG, &token );
  528.                if      ( compare_token( &token, "Content-Type") )
  529.                {
  530.                   do
  531.                   {
  532.                      acquire_token( buf, NAME, &token );
  533.                      if ( compare_token( &token, "name" ) )
  534.                      {
  535.                         acquire_token( buf, CONTENT, &token );
  536.  
  537.                         if ( ( replace_flag ) ||
  538.                              ( firsttime == 0 ) )
  539.                         {
  540.                            sscanf( token.text, "%s", dumname );
  541.                            fixname( dumname );
  542.  
  543.                            if ( strcmpi( dumname, fileargs[1] ) != 0 )
  544.                            {
  545.                               replace_flag = 0;
  546.                            }
  547.                            else
  548.                            {
  549.                               if ( perm_replace_flag )
  550.                               {
  551.                                  printf( 
  552.                                  "More than one output file named %s\n",
  553.                                  dumname );
  554.  
  555.                                  exit(-1);
  556.                               }
  557.                            }
  558.                         }
  559.                      }
  560.                   } while ( token.type != NONE );
  561.                }
  562.                else if ( compare_token( &token, "Content-transfer-encoding" ) )
  563.                {
  564.                   skipflag = 1;
  565.  
  566.                   do
  567.                   {
  568.                      acquire_token( buf, NAME, &token );
  569.                      if ( compare_token( &token, "base64" ) )
  570.                      {
  571.                         skipflag = 0;
  572.                      }
  573.                   } while ( token.type != NONE );
  574.                }
  575.                continue;
  576.             }
  577.             else if ( skipflag != 0 )
  578.             {
  579.                continue;
  580.             }
  581.          }
  582.  
  583.          if ( printmsg )
  584.          {
  585.             if ( skipflag )
  586.             {
  587.                printf( "Section %s not MIME base64\n", dumname );
  588.             }
  589.             else
  590.             {
  591.                printf( "Creating %s\n", dumname );
  592.                if ( strcmpi( dumname, fileargs[1] ) == 0 )
  593.                {
  594.                   replace_flag = 1;
  595.                }
  596.  
  597.                if ( replace_flag )
  598.                {
  599.                   fout = fopen( "$$$$$$$$.$$$", "wb" );
  600.                }
  601.                else
  602.                {
  603.                   fout = fopen( dumname, "wb" );
  604.                }
  605.  
  606.                if ( fout == 0 )
  607.                {
  608.                   printf( "Couldn't open %s for output\n", dumname );
  609.                }
  610.             }
  611.  
  612.             printmsg = 0;
  613.          }
  614.  
  615.          if ( fout == 0 )
  616.          {
  617.             printf( "No filename given for subsequent section\n" );
  618.             exit(-1);
  619.          }
  620.  
  621.          if ( feof(fin) )
  622.          {
  623.             quit = 1;
  624.          }
  625.  
  626.          if ( quit != 0 )
  627.          {
  628.             buf[0] = '\0';
  629.          }
  630.  
  631.          for ( index = 0; (buf[index] != '\n') && (buf[index] != '\0'); index++)
  632.          {
  633.             value = cvt_ascii( buf[index] );
  634.  
  635.             if ( value < 64 )
  636.             {
  637.                accum <<= 6;
  638.                shift += 6;
  639.                accum |= value;
  640.                if ( shift >= 8 )
  641.                {
  642.                   shift -= 8;
  643.                   value = accum >> shift;
  644.                   blivit = (unsigned char)value & 0xFFl;
  645.                   fputc( blivit, fout );
  646.                }
  647.             }
  648.             else
  649.             {
  650.                quit = 1;
  651.                break;
  652.             }
  653.          }
  654.       }
  655.    }
  656.    else
  657.    {
  658.       fprintf ( fout,
  659.        "Content-Type: text/plain; charset=US-ASCII; name=%s\n"
  660.        "Content-transfer-encoding: base64\n\n", fileargs[1] );
  661.  
  662.       shift = 0;
  663.       accum = 0;
  664.       index = 0;
  665.       while ( ( !feof( fin ) ) || (shift != 0) )
  666.       {
  667.          if ( ( !feof( fin ) ) && ( quit == 0 ) )
  668.          {
  669.             blivit = fgetc( fin );
  670.  
  671.             if ( feof( fin ) )
  672.             {
  673.                quit = 1;
  674.                save_shift = shift;
  675.                blivit = 0;
  676.             }
  677.          }
  678.          else
  679.          {
  680.             quit = 1;
  681.             save_shift = shift;
  682.             blivit = 0;
  683.          }
  684.  
  685.          if ( (quit == 0) || (shift != 0) )
  686.          {
  687.             value = (unsigned long)blivit;
  688.             accum <<= 8;
  689.             shift += 8;
  690.             accum |= value;
  691.          } /* ENDIF */
  692.  
  693.          while ( shift >= 6 )
  694.          {
  695.             shift -= 6;
  696.             value = (accum >> shift) & 0x3Fl;
  697.             blivit = alphabet[value];
  698.  
  699.             buf[index++] = blivit;
  700.             if ( index >= 60 )
  701.             {
  702.                buf[index] = '\0';
  703.                fprintf( fout, "%s\n", buf );
  704.                index = 0;
  705.             }
  706.  
  707.             if ( quit != 0 )
  708.             {
  709.                shift = 0;
  710.             }
  711.          }
  712.       }
  713.  
  714.       if      ( save_shift == 2 )
  715.       {
  716.          buf[index++] = '=';
  717.          if ( index >= 60 )
  718.          {
  719.             buf[index] = '\0';
  720.             fprintf( fout, "%s\n", buf );
  721.             index = 0;
  722.          }
  723.  
  724.          buf[index++] = '=';
  725.          if ( index >= 60 )
  726.          {
  727.             buf[index] = '\0';
  728.             fprintf( fout, "%s\n", buf );
  729.             index = 0;
  730.          }
  731.       }
  732.       else if ( save_shift == 4 )
  733.       {
  734.          buf[index++] = '=';
  735.          if ( index >= 60 )
  736.          {
  737.             buf[index] = '\0';
  738.             fprintf( fout, "%s\n", buf );
  739.             index = 0;
  740.          }
  741.       }
  742.  
  743.       if ( index != 0 )
  744.       {
  745.          buf[index] = '\0';
  746.          fprintf( fout, "%s\n", buf );
  747.       }
  748.    }
  749.  
  750.    fclose( fout );
  751.  
  752.    if ( replace_flag )
  753.    {
  754.       perm_replace_flag = 1;
  755.  
  756.       if ( ( whattodo == DECODE ) && ( decode_state <= 0 ) )
  757.       {
  758.          remove( "$$$$$$$$.$$$" );
  759.          printf( "No MIME base64 lines found in %s\n", fileargs[1] );
  760.       }
  761.    }
  762.    else
  763.    {
  764.       if ( ( whattodo == DECODE ) && ( decode_state <= 0 ) )
  765.       {
  766.          remove( fileargs[2] );
  767.          printf( "No MIME base64 lines found in %s\n", fileargs[1] );
  768.       }
  769.    }
  770.  
  771.    fout = 0;
  772.    firsttime = 0;
  773.    dumname[0] = '\0';
  774.    cycle_flag = 0;
  775.  
  776. } while ( !feof( fin ) );
  777.  
  778.  
  779. if ( perm_replace_flag )
  780. {
  781.    remove( fileargs[1] );
  782.    rename( "$$$$$$$$.$$$", fileargs[1] );
  783. }
  784.  
  785. fclose( fin );
  786. }
  787.